package de.koller.singularity.client.display;

import de.koller.oceanFramework.thread.IPipe;
import de.koller.oceanFramework.thread.Pipeline;
import de.koller.oceanFramework.tree.Mother;
import de.koller.singularity.SNode;
import de.koller.singularity.engine.SEngine;
import de.koller.singularity.engine.tile.STile;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

public class TileDisplay extends SNode {

	public static final int DISPLAY_THREADS = 8;
	@Mother private SDisplay display;
	private long offsetX = 0, offsetY = 0;

	private Pipeline pipeline;
	private STile[][][] tileDisplayBuffer;
	private Graphics2D graphics;
	
	@Override
	protected void init() {
		super.init();
		
		int tw = display.plainDisplay.width / SEngine.TILE_SIZE;
		int th = display.plainDisplay.height / SEngine.TILE_SIZE;
		
		tileDisplayBuffer = new STile[ tw ][ th ][];
		
		TileRenderPart[] parts = new TileRenderPart[ DISPLAY_THREADS ];
		for( int i = 0; i < DISPLAY_THREADS; i++ ) {
			int w = Math.round( tw / (float)DISPLAY_THREADS +.5f );
			parts[i] = new TileRenderPart( w * i, w );
		}
		pipeline = new Pipeline( parts );
	}
	
	public void renderTiles( Graphics2D g ) {
		int tw = display.plainDisplay.width / SEngine.TILE_SIZE;
		int th = display.plainDisplay.height / SEngine.TILE_SIZE;
		
		for( int tx = 0; tx < tw; tx++ )
			for( int ty = 0; ty < th; ty++ ) {
				tileDisplayBuffer[tx][ty] = sroot.engine.tilemap.getTileAt( "default", 
						tx + offsetX, ty + offsetY );
			}
		
		graphics = g;
		pipeline.stepPipes();
	}
	
	public long[] screenToWorld( int x, int y ) {
		long tx = x / SEngine.TILE_SIZE;
		long ty = y / SEngine.TILE_SIZE;
		tx += offsetX;
		ty += offsetY;
		return new long[] { tx, ty };
	}
	
	public void incCamera( int tx, int ty ) {
		offsetX += tx;
		offsetY += ty;
	}
	
	private class TileRenderPart implements IPipe {

		private final int xStart, calcW;
		private final BufferedImage rc;
		private final Graphics2D g;
		
		public TileRenderPart( int xStart, int calcW ) {
			this.xStart = xStart;
			this.calcW = calcW;
			
			rc = new BufferedImage( calcW * SEngine.TILE_SIZE, 
					tileDisplayBuffer[0].length * SEngine.TILE_SIZE, 
					BufferedImage.TYPE_INT_RGB );
			g = rc.createGraphics();
		}
		
		@Override
		public void updateSubStep() {
			for( int tx = xStart; tx < xStart+calcW; tx++ ) {
				if( tx >= tileDisplayBuffer.length )
					continue;
				for( int ty = 0; ty < tileDisplayBuffer[tx].length; ty++ ) {
					STile[] t = tileDisplayBuffer[tx][ty];
					if( t == null ) continue;
					for( int j = 0; j < t.length; j++ )		
						t[j].sprite.render( g, 
								(tx-xStart) * SEngine.TILE_SIZE, 
								ty * SEngine.TILE_SIZE, 
								SEngine.TILE_SIZE, 
								SEngine.TILE_SIZE, 
								0 );
				}
			}
			
			graphics.drawImage( rc, xStart*SEngine.TILE_SIZE, 0, null );
		}

		@Override public String getName() { return "tileDiplayRender"; }
		
	}
	
}
